<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * BackendPro
 *
 * A website backend system for developers for PHP 4.3.2 or newer
 *
 * @package         conlabz CMS
 * @author          Christian Schneider
 * @copyright       Copyright (c) 2009
 * @license         
 * @link            http://www.conlabz.de
 * @filesource
 */

// ---------------------------------------------------------------------------

include_once(APPPATH . 'models/Nested_sets_model.php');

/**
 * Category Model
 *
 * Provides functionaly to interact with the category tables
 * in the database
 *
 * @package         conlabz CMS
 * @subpackage      Models
 */
class category_model extends Base_model { 
	
	var $category;

	function category_model( ){
		parent::Base_model();

		$this->_TABLES['category'] = "category";
		$this->category = new Nested_sets_model();
		$this->category->setControlParams( $this->_TABLES['category'] );
		$this->category->setPrimaryKeyColumn( 'id' );
		
		log_message( 'debug', 'conlabz CMS : category_model class loaded');
	}


	/**
	 * Create Pretty Offset
	 *
	 * Creates a pretty text offset to display nested items using basic text
	 *
	 * @access public
	 * @param object $obj Reference to a Nested_sets_model object, e.g. $this->group, $this->resource
	 * @param array $tree Current Tree array
	 * @param string $next_ancestor_sibling String prepended to offset if there is a next sibling after the current ancestor
	 * @param string $no_next_ancestor_sibling String prepended to offset if there is no next sibling after the current ancestor
	 * @param string $last_sibling String appended to offset if this is the last node of the current level
	 * @param string $not_last_siling String appended to offset if this is not the last node of the current level
	 */
	function buildPrettyOffset($obj, $tree,
		$next_ancestor_sibling = "|&nbsp;&nbsp; ",
		$no_next_ancestor_sibling = "&nbsp;&nbsp;&nbsp; ",
		$last_sibling = "`- ",
		$not_last_sibling = "|- ")
	{
		$lvl = $obj->getTreeLevel($tree);

		// Nest the tree
		$offset = '';
		if($lvl > 1)
		{
			$ancestor = $obj->getAncestor($tree['row']);
			while( ! $obj->checkNodeIsRoot($ancestor))
			{
				if($obj->checkNodeHasNextSibling($ancestor))
				{
					// Ancestor has sibling so put a | in offset
					$offset = $next_ancestor_sibling . $offset;
				}
				else
				{
					// No next sibling just put space
					$offset = $no_next_ancestor_sibling . $offset;
				}
				$ancestor = $obj->getAncestor($ancestor);
			}
		}

		// If this is the last node add branch terminator
		if($obj->checkNodeHasNextSibling($tree['row']))
		{
			$offset .= $not_last_sibling;
		}
		elseif($lvl != 0)
		{
			$offset .= $last_sibling;
		}
		return $offset;
	}

	/**
	 * Build Pretty array for dropdown
	 *
	 * Constructs an array of the given tree to be used for a dropdown menu
	 *
	 * @access public
	 * @param string $tree_id Tree ID, always category
	 * @param string $value_field Table field to use as the option value
	 * @return array
	 */
	function buildCategoryDropdown( $tree_id = NULL, $value_field = 'name', $where = ''  )
	{
		if( $tree_id != 'category' ) {
			show_error( "conlabz CMS->category_model->buildCategroyDropDown: The tree_id for the dropdown must be 'category'.");
		}

		$obj =& $this->{ $tree_id };
		$tree = $obj->getTreePreorder( $obj->getRoot( ), $where );

		$dropdown = array( );
		while( $obj->getTreeNext( $tree ) )	{
			// Get offset
			$offset = $this->buildPrettyOffset( $obj, $tree );

			$dropdown[$tree['row'][$value_field]] = $offset . $tree['row']['name'];
		}
		return $dropdown;
	}

	/**
	 * Build Pretty array for dropdown
	 *
	 * Constructs an array of the given tree to be used for a dropdown menu
	 *
	 * @access public
	 * @param string $tree_id Tree ID, always category
	 * @param string $value_field Table field to use as the option value
	 * @return array
	 */
	function buildCategoryUnorderedList( $tree_id = NULL, $where = '' )
	{
		if( $tree_id != 'category' ) {
			show_error( "conlabz CMS->category_model->buildCategroyUnorderedList: The tree_id for the dropdown must be 'category'.");
		}

		$obj =& $this->{ $tree_id };
		$tree = $obj->getTreePreorder( $obj->getRoot( ), $where );

		$list = '<ul>';
		while( $obj->getTreeNext( $tree ) )	{
			// Get offset
			$offset = $this->buildPrettyOffset( $obj, $tree );

			//$list[$tree['row'][$value_field]] = $offset . $tree['row']['name'];
			//@todo: language should be better
			$list .= '<li>
						<table width="100%">
        					<tr>
            					<td width="70%">'.$offset . $tree['row']['name'].'</td>
					            <td width="16%" class="middle"><a href="'. site_url( 'article/user/category/form/'.$tree['row']['id'] ).'">'. $this->bep_assets->icon( 'pencil' ) .'</a></td>
					            <td width="16%" class="middle"><a href="'. site_url( 'article/user/category/form/'.$tree['row']['id'] ).'/2">'. $this->bep_assets->icon( 'flag-gb' ) .'</a></td>
					            <td width="14%">'. form_checkbox( 'select[]', $tree['row']['id'], FALSE ) .'</td>
					        </tr>
						</table>
					  </li>'; 
		}
		$list .= '</ul>';
		return $list;
	}

	/**
	 * Build Action Selector
	 *
	 * Constructs the interface to be used when creating/modifying a permission.
	 * It allows the user to select what actions if any the permission has.
	 *
	 * @access public
	 * @return string
	 */
	function buildActionSelector()
	{
		$value = '';
		$query = $this->fetch('axos');
		foreach($query->result() as $action)
		{
			$checkbox = 'action_'.$action->id;
			$radio = 'allow_'.$action->id;
			$value .= form_checkbox($checkbox,$action->name,$this->validation->set_checkbox($checkbox,$action->name));
			$value .= $action->name . "<br>\n";

			$value .= '<div id="'.$radio.'" class="action_item">';
			$value .= form_radio($radio,'Y',$this->validation->set_radio($radio,'Y')) . $this->lang->line('access_allow');
			$value .= form_radio($radio,'N',$this->validation->set_radio($radio,'N')) . $this->lang->line('access_deny') . '</div>';
		}
		return $value;
	}

	/**
	 * Build Resource Selector
	 *
	 * Used to build the tree like radio button interface to select a resource
	 *
	 * @access public
	 * @param boolean $disabled Whether the radio buttons should be clickable
	 * @return string
	 */
	function buildResourceSelector($disabled = FALSE)
	{
		return $this->_buildSelector($disabled,'aco');
	}

	/**
	 * Build Group Selector
	 *
	 * Used to build the tree like radio button interface to select a group
	 *
	 * @access public
	 * @param boolean $disabled Whether the radio buttons should be clickable
	 * @return string
	 */
	function buildGroupSelector($disabled = FALSE)
	{
		return $this->_buildSelector($disabled,'aro');
	}

	/**
	 * Build Selector
	 *
	 * Abstract method to construct a generic tree like radio button interface
	 *
	 * @access private
	 * @param boolean $disabled Whether the radio buttons should be clickable
	 * @param string $type Table ID to use, either 'aro' => 'group', or 'aco' => 'resource'
	 * @return string
	 */
	function _buildSelector($disabled,$type)
	{
		// Value to return
		$value = '';

		// Set the table type
		switch($type)
		{
			case 'aco': $obj = & $this->resource; break;
			case 'aro': $obj = & $this->group; break;
		}

		$disabled = ($disabled) ? ' disabled' : '';

		// Create Selector
		$tree = $obj->getTreePreorder($obj->getRoot());
		$lvl = 0;
		while($obj->getTreeNext($tree))
		{
			// Nest the tree
			$newLvl = $obj->getTreeLevel($tree);
			if ($lvl > $newLvl)
			{
				// Just gone up some levels
				$value .= str_repeat("</ul></li>",$lvl-$newLvl);
			}
			$lvl = $newLvl;

			$set = $this->validation->set_radio($type,$tree['row']['name']);

			// If no node is set and this is the root, set it
			if( ! is_null($set) AND $obj->checkNodeIsRoot($tree['row']))
			$set = ' checked';

			$open = ( ! is_null($set)) ? ' class="open"' : '';
			$value .='<li id="'.$tree['row']['id'].'"'.$open.'>'.form_radio($type,$tree['row']['name'],$set,$disabled).'<span>'.$tree['row']['name'].'</span>';

			if($obj->checkNodeHasChildren($tree['row']))
			{
				$value .= "<ul>";
			}
			else
			{
				$value .= "</li>";
			}
		}

		// Close Tree
		$value .= str_repeat("</ul></li>",$lvl);

		return $value;
	}

	/**
	 * Get Categories
	 *
	 * @access public
	 * @param mixed $where Where query string/array
	 * @param array $limit Limit array including offset and limit values
	 * @return object
	 */
	function getCategories( $where = NULL, $limit = array( 'limit' => NULL, 'offset' => '' ) ) {
		$this->db->select( 'category.id,
							category.name,
							category.url_title'
						   );
		$this->db->from( "category" );
		if( !is_null( $where ) ){
			$this->db->where( $where );
		}
		if( !is_null( $limit['limit'] ) ){
			$this->db->limit( $limit['limit'], ( isset( $limit['offset'] ) ? $limit['offset'] : '' ) );
		}
		return $this->db->get( );
	}
	
	/**
	 * Get Category Language ID
	 *
	 * @access public
	 * @param int $id Category id
	 * @return int
	 */
	function getCategoryLanguageId( $id ){
		$this->db->select( 'language_id' );
		$this->db->from( "category" );
		$this->db->where( "id = " . $id );
		
		$query = $this->db->get( );
		foreach ($query->result() as $row) {
   			$lang_id = $row->language_id;
		}
		return $lang_id;
	}
	
	/**
	 * Get Category ID
	 *
	 * @access public
	 * @param int $id Category id
	 * @return int
	 */
	function getCategoryID( $id ) {
		$this->db->select( 'id' );
		$this->db->from( "category" );
		$this->db->where( "id = " . $id );
		
		$query = $this->db->get( );
		foreach( $query->result( ) as $row ) {
   			$cagegory_id = $row->id;
		}
		return $cagegory_id;
	}
	
	/**
	 * Get maximal Category ID
	 *
	 * @access public
	 * @param int $id Category id
	 * @return int
	 */
	function _getMaxCategoryId( ){
		$this->db->select_max( 'id' );
		$query = $this->db->get( 'category' );
		$row = $query->row( );
		return $row->id;
	}
	
	/**
	 * Insert new Category
	 *
	 * @access public
	 * @param array $data Data array
	 */
	function insert( $data = array( ) ) {
		// http://www.freude-co.de/2008/07/21/nested-set-model/
		// SELECT @myRight := rgt FROM nested_category WHERE name = 'TELEVISIONS';		
		$this->db->select( 'rgt' );
		$this->db->where( 'id', $data['category_id'] );
		$this->db->where( 'language_id', $data['language_id'] ); 
		$query = $this->db->get( 'category' );
		$row = $query->row( );
		// UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myRight;
		$this->db->query( 'UPDATE category SET rgt = rgt + 2 WHERE rgt >= ' . $row->rgt . ' AND language_id =' .$data['language_id'] );
		// UPDATE nested_category SET lft = lft + 2 WHERE lft > @myRight;
		$this->db->query( 'UPDATE category SET lft = lft + 2 WHERE lft >= ' . $row->rgt . ' AND language_id =' .$data['language_id'] );
		// INSERT INTO nested_category(name, lft, rgt) 
		// VALUES('GAME CONSOLES', @myRight + 1, @myRight + 2)
		$data['lft'] = ( $row->rgt );
		$data['rgt'] = ( $row->rgt + 1 );
		$data['id'] = $this->_getMaxCategoryId( ) + 1;
		unset( $data['category_id'] );
		//create new category entry
		$this->db->insert( 'category', $data );
	}
	
	/**
	 * Update Category
	 *
	 * @access public
	 * @param int $id Object id
	 * @param array $data Data array
	 */
	function update( $data = array( ), $id = 0 ) {
		//@todo: needs to be checked if it is correct!
		//get category_language_id by category_id
		$data['category_language_id'] = $this->category_model->getCategoryLanguageId( $data['category_id'] );
		
		//update categroy
		$this->db->update( 'category', 
						   $data, 
						   array( 'id' => $id,
						   		  'website_id' => $data['website_id'] )
						 );	
	}
	
	/**
	 * Delete Category entry
	 *
	 * @access public
	 * @param int $category Object ID
	 */
	function delete( $category_id ){
		/* from: http://www.klempert.de/nested_sets/#kap5
		 * DELETE FROM tree WHERE lft = $LFT;
		 * UPDATE tree SET lft=lft-1, rgt=rgt-1
		 * 		 WHERE lft BETWEEN $LFT AND $RGT;
		 * UPDATE tree SET lft=lft-2 WHERE lft>$RGT;
		 * UPDATE tree SET rgt=rgt-2 WHERE rgt>$RGT;
		 ***/
		//get rgt value of actual entry
		$this->db->select( 'rgt, lft' );
		$this->db->where( 'id', $category_id ); 
		$query = $this->db->get( 'category' );
		$row = $query->row( );
		
		$this->db->delete( 'category', array( 'lft' => $row->lft ) );
		$this->db->query( 'UPDATE category SET lft=lft-1, rgt=rgt-1 WHERE lft BETWEEN ' . $row->lft . ' AND ' . $row->rgt );
		$this->db->query( 'UPDATE category SET lft=lft-2 WHERE lft > ' . $row->rgt );
		$this->db->query( 'UPDATE category SET rgt=rgt-2 WHERE rgt > ' . $row->rgt );		
	}
}
/* End of file: access_control_model.php */
/* Location: ./modules/auth/models/access_control_model.php */